/* 
 * File:   FractalPrinter.cpp
 * Author: amouro-m
 * 
 * Created on 18 mai 2010, 09:36
 */

#include "FractalPrinter.h"

void
FractalPrinter::putpixel(SDL_Surface *surface, int x, int y, Uint32 color)
{
	int bpp = surface->format->BytesPerPixel;
	Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

	switch(bpp) {
	case 1:
		*p = color;
		break;

	case 2:
		*(Uint16 *)p = color;
		break;

	case 3:
		if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
			p[0] = (color >> 16) & 0xff;
			p[1] = (color >> 8) & 0xff;
			p[2] = color & 0xff;
		} else {
			p[0] = color & 0xff;
			p[1] = (color >> 8) & 0xff;
			p[2] = (color >> 16) & 0xff;
		}
		break;

	case 4:
		*(Uint32 *)p = color;
		break;
	}
}

Uint32
FractalPrinter::getpixel(const SDL_Surface *surface, unsigned int x, unsigned int y)
{
    int bpp = surface->format->BytesPerPixel;
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
    return *(Uint32 *)p;
}

FractalPrinter::FractalPrinter(SDL_Surface* area):
_area(area),
_fractal(NULL)
{}

FractalPrinter::FractalPrinter(SDL_Surface* area, Fractal* fractal):
_area(area),
_fractal(fractal)
{
    update();
}

FractalPrinter::~FractalPrinter() {}

Fractal*
FractalPrinter::get_fractal() const
{
    return _fractal;
}

unsigned int
FractalPrinter::get_width() const
{
    return _nb_point_added + _area->w;
}

unsigned int
FractalPrinter::get_height() const
{
    return _nb_point_added + _area->h;
}

SDL_Surface*
FractalPrinter::get_area() const
{
    return _area;
}

void
FractalPrinter::set_fractal(Fractal* fractal)
{
    if(fractal)
    {
        _fractal = fractal;
        update();
    }
}

void
FractalPrinter::compute(unsigned int x, unsigned int y)
{
    double X = _fractal->_xmin + (x * _coefx_to_fractal);
    double Y = _fractal->_ymin + (y * _coefy_to_fractal);
    Uint32 c8 = _fractal->compute(X, Y);
    Uint32 c32 = SDL_MapRGBA(_area->format, 0, 0, c8*16, 0);
    unsigned int areax = coordX(X);
    unsigned int areay = coordY(Y);
    //putpixel(_area, areax, areay, c32);
    putpixel(_area, areax, areay, c8);
}

void
FractalPrinter::repaint()
{
    emit updated();
}

void
FractalPrinter::update()
{
    _coefx_to_fractal = (_fractal->_xmax - _fractal->_xmin) / (_area->w + _nb_point_added);
    _coefy_to_fractal = (_fractal->_ymax - _fractal->_ymin) / (_area->h + _nb_point_added);

    _coefx_to_area = _area->w / (_fractal->_xmax - _fractal->_xmin);
    _coefy_to_area = _area->h / (_fractal->_ymax - _fractal->_ymin);
}

unsigned int
FractalPrinter::coordX(double x) const
{
    return (x - _fractal->_xmin) * _coefx_to_area;
}

unsigned int
FractalPrinter::coordY(double y) const
{
    return (y - _fractal->_ymin) * _coefy_to_area;
}